    ____________________  _____  ______________________________ ______________
   /        /  ______/  |/    / /   _____/  ____  /  ___   /   /    /  ____  /
  /   /    /_____   /        / /   /_   /  ______/        /   /    /  ______/
 /___,____/________/___|/___/ /________/___/ /__|________/________/___/
 -asmgroup-------------------------------------------------www.asmpage.prv.pl-

 title:Jak zlamac crackme nr 1 by Cauchy ?   date:04.08.2003
 autor:Reverend
 homepage:http://asmpage.prv.pl              mail:rev15@wp.pl

 -begin-----------------------------------------------------------------------

 Rodzaj zabezpieczenia: Serial
 Czym zlamiemy: IDA 4.04, IceDump, MASM, Softice

 Witam !
 Zaczniemy od wstepnego rozpoznania zabezpieczenia. Sprawdzmy czy proggie jest 
 spakowany.   Mozna   to  zrobic  na  kilka  sposobow.  Ja  wykorzystalem  ten
 najprostszy, tzn. podejrzalem plik w edytorze tekstu ;). Na pierwszy rzut oka 
 widac  ze mamy tu namieszane z sekcjami, poniewaz widac tylko sekcje Cauchy i
 .rsrc  Wydalo  mi  sie  to  podejrzane.  Dlatego probujac zdisasemblowac plik
 upewnilem sie, ze plik jest spakowany. Radze go rozpakowac juz w tym momencie 
 (nie bede opisywal jak to zrobic, bo bylo to juz w wielu innych tutorialach i 
 nie  jest  to glownym tematem mojego tutka). Rozpakowany plik wrzucamy do IDY
 (w  ostatecznosci  niech  bedzie wdasm ale pozniej beda problemy). Znajdujemy
 adres 004010EA pod ktorym znajduje sie wywolanie funkcji GetDlgItemTextA. Oto 
 co widzimy ponizej:
  		cmp	eax, 13h         ; hmm... 13h = 19d
 		ja	short loc_401098 ; jezeli wiecej to skacz
 		mov	ecx, eax         ; zachowaj ilosc liter w ecx
 		mov	esi, 403045h     ; do ESI idzie to co wpisalismy
 		mov	edi, 40307Ch     ; do EDI idzie pusty bufor
 		push	edi              ; EDI na stos
 Widzimy,  ze  ilosc  liter  wpisanych  jest porownywana z 19 i jesli jest ich
 wiecej to skok. Mozesz sprawdzic, gdzie skacze ta instrukcja, ale ja juz wiem
 ze nie to jest nam do szczescia potrzebne ;). Nizej widzimy instrukcje jakie 
 zostana wykonane. Na razie zostawmy je w spokoju ;) Wazna dla nas informacje 
 mozna odczytac dalej. Przeanalizujmy ponizszy fragment kodu:
  		mov	eax, [edi]       ; w   EDI  jest  pozmieniany  wpisany
  		                         ; serial
 		mov	ebx, 0           ; zapamietaj EBX = 0
 		xor	eax, 0DEAD666h   ; xoruje  pierwsze  cztery  znaki  (w
 		                         ; odwrotnej kolejnosci)
 		call	sub_4011FA       ; wywolanie jakiejs funkcji
		sub	eax, ebx         ; hmm.. ta funkcja musi zwracac cos w 
		                         ; ebx, poniewaz
		jnz	loc_401098       ; wartosc w eax i ebx musi  byc rowna
		                         ; a EBX bylo rowne 0
		mov	eax, [edi+4]     ; kolejne 4 znaki
		xor	eax, 6F7B930Ch   ; xor,  ktory w polaczeniu z kolejnym
		                         ; skokiem mowi nam, ze
		jnz	loc_401098       ; ze  kolejne  cztery  znaki maja byc
		                         ; rowne wlasnie tej wartosci
		add	edi, 8           ; znowu, cztery
		mov	eax, [edi]       ; znaki do EAX
		cmp	eax, 6F880A85h   ; czy EAX = ta wartosc
		jnz	loc_401098       ; jesli  nie  to  _badboy, a tego nie
		                         ; chcemy
		sub	edi, 4           ; zgadnij ;)
		mov	eax, [edi+8]     ; 4 znaki do EAX
		sub	eax, 7C5C11A7h   ; maja byc tyle rowne
 Chce  tutaj  jeszcze  wyjasnic  sprawe  tej  funkcji wywolywanej w 4 linijce.
 Mozesz  oczywiscie  zobaczyc  co  ona robi. Wystarczy zauwazyc, ze generowane
 przez  funkcje  wartosc  nie  jest  od  niczego zalezna i zawsze zwraca w EBX
 wartosc 3C0AC61Bh, dlatego linijki:
 		xor	eax, 0DEAD666h
 		call	sub_4011FA
 		sub	eax, ebx
 mozna zamieni na
		xor	eax, 0DEAD666h
 		sub	eax, 3C0AC61Bh
 co mozna zamienic na
 		sub	eax, 31E0107Dh
 i  wyjdzie  na  to  samo,  ale  bardziej  czytelnie ;).  Przejdziemy teraz do
 najgorszej   czesci,    czyli  algo  generujacego  prawidlowy  serial.  Pisze
 najgorszej,  bo przyznam sie szczerze ze znalezienie prawidlowego rozwiazania
 wcale  nie  bylo  dla  mnie drobnostka i po kilku godzinach znienawidzilem ta
 czesc ;). Do roboty:
                dec	ecx
 loc_401102:
 		push	ecx        <------------------------------------|
 		mov	al, [esi]                                       |
 loc_401105:                                                            |
 		sub	al, 30h    <------------------------------ |    |
 		xor	al, 75h                                    |    |
 		rol	al, 0Fh                                    |1   |
 		add	al, al                                     |    |
 		loop	loc_401105 >-------------------------------|    |
 		pop	ecx                                             |
 		push	ecx                                             |
 		mov	bl, [esi+1]                                     |3
 loc_401115:                                                            |
 		sub	bl, 7      <-------------------------------|    |
 		ror	bl, 5                                      |    |
		add	bl, 2Fh                                    |2   |
 		xor	bl, 0DFh                                   |    |
  		loop	loc_401115 >-------------------------------|    |
 		pop	ecx                                             |
 		xor	al, bl                                          |
 		mov	[edi], al                                       |
 		inc	edi                                             |
 		inc	esi                                             |
		loop	loc_401102 >------------------------------------|
  		pop	edi
 Troche  tego  jest.  Ale  zacznijmy od poczatku. W oczy rzucaja sie od razu 3
 petle.   Dzialaja   one   na  podstawie  instrukcji  loop,  ktora  skacze  do
 wskazywanego  adresu  (popatrz na strzalki) dopoki ecx nie jest rowne 0. Loop
 takze  przy kazdym sprawdzeniu aktualnego stanu ecx zmniejsza je o 1. Ale ile
 jest  w  ecx ? Cofnijmy sie troche. Tak - do ecx trafia ilosc wpisanych przez
 nas liter.  To oznacza, ze musimy juz teraz wiedziec ile nalezy wpisac liter,
 bo pomylka kosztowalaby nas wiele czasu, bo kazda wpisana nowa litera zmienia 
 zupelnie  wygenerowany  ciag  znakow. Zobaczmy na poprzedni listing. Mamy tam
 cztery porownania (po cztery bajty kazdy), czyli musi powstac 16 znakow ASCII 
 w naszym prawidlowym hasle. Wydawaloby sie, ze nalezy w takim wypadku  wpisac
 16  liter.  Gdybysmy  tak  zrobili  to  bylby  to  nasz  najwiekszy  blad !!!
 Przyjrzyjmy  sie  uwaznie  temu  algo.  Do  al trafia pierwszy znak i zostaje
 pozmieniany  przez  instrukcje  zawarte w pierwszej petli. Zauwaz, jednak, ze
 ecx  jest  dekrementowane  (zmniejszane o 1) j ednokrotnie przed rozpoczeciem
 generowania  seriala.  Czyli  petla  jest wykonywana tyle razy ile wpisalismy
 znakow-1.  Mam  nadzieje  ze to rozumiesz. Dzieki seriom push'y i pop'ow stan
 ecx pozostaje taki sam przy dojsciu  do  kazdej  nowej  petli.  Za  wyjatkiem
 oczywiscie ostatniej, ktora  po  zakonczeniu  dzialania  na  pierwszym  znaku
 zmniejsza sie o 1. To oznacza, ze jesli wpiszemy np. 4 znaki to pierwszy znak 
 przejdzie przez petle 3 (4-1=3) razy, drugi 2...... Kontunuujmy analize.  Jak
 juz napisalem al jest pozmieniane przez pierwsza petle, a  drugi  znak  ktory
 znajduje sie  teraz  w  bl  przechodzac  przez  petle  2  zostaje  calkowicie
 zmieniany. Potem te dwie wartosci sa ze  soba  xorowane  i  wynik  trafia  na
 miejsce   pierwszego  wpisanego  przez  nas  znaku.  Na  koniec  edi  zostaje
 podniesione o 1, czyli kolejnym  razem  petla  przekonwertuje  kolejny  znak.
 Oznacza to, ze 1 znak z 2 daja pierwszy znak wynikowy, 2 z 3 daja drugi  znak
 wynikowy ..... 16 z 17 daja  szesnasty  znak  wynikowy.  No  wlasnie.  Musimy
 wpisac 17 znakow. Analiza zakonczona.

 Teraz zajmijmy sie wygenerowaniem prawidlowego seriala. Przyznam sie szczerze 
 ze niezle sie z tym umeczylem. Ja zdecydowalem sie w tym przypadku  na  brute
 force. Zrobilem tak z kilku powodow.
 Po pierwsze: mamy az 255 (00h  nie  moze  byc)  mozliwosci pierwszego  znaku,
 ale nie dla kazdej wartosci istnieje taki inny  znak,  ktoryby  po  przejsciu
 przez te petle wciaz spelnial warunki,  mozna wtedy  latwo  wyeliminowac  zle
 ciagi i nie kontynowac ich dalszego generowania. Moge juz teraz powidziec, ze 
 ten program na moim sprzecie (oj, kiepsko u mnie z  szybkoscia ;))  wykonywal
 sie niecala sekunde.
 Po drugie: troszke mniej zlozone, jednak bardzo wazne. Nie umialem i do teraz
 nie wiem, czy w ogole mozna jakos odwrocic te wszystkie petle ;))) Jesli jest
 to jakos mozliwe to mail me, chce sie dowiedziec chociaz po fakcie
 Po trzecie: w sumie,  to  jak  dodalem  mozliwosc wykluczenia zlych ciagow to
 program  przestal  byc brute force, teraz wypisuje wszystkie mozliwe seriale,
 ktore sa prawidlowe, wiec mozna powiedzsiec, ze jest swojego rodzaju keygenem

 Dosyc gledzenia.
 Przedstawie tu tylko najwazniejsze i najbardziej istotne dla mojego  programu
 czesci. W dziale .DATA musimy koniecznie ustawic prawidlowy ciag, z ktorym ma 
 byc porownywany nasz dummy serial. Pamietaj, ze dane z pamieci czyta  sie  od
 tylu, dlatego musimy kazdy cztery bajty zamienic. U mnie wyszlo to tak:
 good   db 7Dh,10h,0E0h,31h,0Ch,93h,7Bh,6Fh,85h,0Ah,88h,6Fh,0A7h,11h,5Ch,7Ch,0
 Atutem brute force jest to, ze mozemy wyripowac cale algo i wpisac do naszego 
 pliku .asm dodajac tylko odpowiedni poczatek i koniec. Tak samo zrobimy teraz
 Musimy stworzyc dwie zmienne typu dd. Dzialanie  mojego  programu  przedstawi
 ponizszy schemat:

 POCZATEK
 do eax wartosc pierwszej zmiennej
 do ecx 16 (17-1 pamietasz jeszcze ?)

 pierwsza petla <----------------------------------------|
 wynik do jakiegos bufora                                |
                                                         |
 przywroc wartosc ecx                                    |
 do ebx wartosc drugiej zmiennej <--------------|        ^
 druga petla                                    |        |
 xor al,bl                                      |        |
 czy rowne wartosci z ciagu good                |        |
 jesli nie to inaczej trzeba ----->--------|    |        |
                                           |    |        ^
 jesli tak to zapamietaj w buforze i wstaw |    |        |
 ta wartosc do pierwszej zmiennej i        |    |        |
 dodaj jeden do wskaznika good i skacz     |    |        |
 do pierwszej petli -------------------------------------^
                                          |    |        |
                                          |    |        |
                                          |    |        |
                                          |    |        |
 dodaj do drugiej zmiennej 1 <-------------|    |        |
 czy druga zmienna jest rowna 255 (0FFh)        |        ^
 jesli nie to ------------>---------------------|        |
                                                        |
 jesli tak to przywroc wartosc pierwszej zmiennej        |
 dodaj jeden do zmiennej                                 |
 wyzeruj druga zmienna                                   |
 skacz do pierwszej petli ----------->-------------------|
 KONIEC

 Mam nadzieje ze cos z tego zrozumiales, chociaz  jak  sam  na  to  patrze  to
 ciezko mi sie pokapowac o co w tym chodzi. Dlatego mozesz oczywiscie zobaczyc 
 zrodlo mojego programu. Powinno byc zalaczone do  tego  textu  lub  wejdz  na
 www.asmpage.prv.pl lub w ostatecznosci pisz na rev15@wp.pl
 Respect
 -thnx'y----------------------------------------------------------------------
 AG, jopas, Tymon, i kazdy wymineony w programie

 -end-------------------------------------------------------------------------
